#include "serialrepeaterwindow.h"
#include "ui_serialrepeaterwindow.h"
#include <QSettings>

SerialRepeaterWindow::SerialRepeaterWindow(QWidget *parent):
    QMainWindow(parent),
    ui(new Ui::SerialRepeaterWindow),
    m_serialportL(nullptr),
    m_serialportR(nullptr),
    m_l2r_cnt(0),
    m_r2l_cnt(0)
{
    ui->setupUi(this);

    QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts();

    foreach (QSerialPortInfo port, ports) {
        ui->portL->addItem(port.portName());
        ui->portR->addItem(port.portName());
    }
    ui->portL->setCurrentIndex(0);
    ui->portR->setCurrentIndex(0);

    QList<qint32> baudRates = QSerialPortInfo::standardBaudRates();
    baudRates.removeOne(110);
    baudRates.removeOne(300);
    baudRates.removeOne(600);
    baudRates.removeOne(1200);
    baudRates.removeOne(14400);
    baudRates.removeOne(56000);
    foreach (qint32 baud, baudRates) {
        ui->baudRateL->addItem(QString::number(baud));
        ui->baudRateR->addItem(QString::number(baud));
    }
    ui->baudRateL->setCurrentIndex(0);
    ui->baudRateR->setCurrentIndex(0);

    connect(ui->action_Start, &QAction::triggered, this, &SerialRepeaterWindow::startActionTriggered);
    connect(ui->action_Stop, &QAction::triggered, this, &SerialRepeaterWindow::stopActionTriggered);
    connect(ui->action_Exit, &QAction::triggered, this, &SerialRepeaterWindow::exitActionTriggered);

    openEnable(false);

    loadConfig();
}

SerialRepeaterWindow::~SerialRepeaterWindow()
{
    delete ui;
}

void SerialRepeaterWindow::loadConfig()
{
    const QString filename(QApplication::applicationName() + QString(".ini"));

    loadDefaultConfig();
    if(QFile(filename).exists()){
        if(readConfig()){
            return;
        }
    }
//    saveConfig();
}

void SerialRepeaterWindow::loadDefaultConfig()
{

}

bool SerialRepeaterWindow::readConfig()
{
    const QString filename(QApplication::applicationName() + QString(".ini"));
    QStringList grouplist;
    QString comL = "ComL";
    QString comR = "ComR";

    QSettings *settings;
    settings = new QSettings(filename, QSettings::IniFormat);
    grouplist = settings->childGroups();
    if(grouplist.contains(comL)){
        settings->beginGroup(comL);
        if(settings->contains(QString("Port"))){
            ui->portL->setCurrentText(settings->value("Port").toString());
        }
        if(settings->contains(QString("BaudRate"))){
            ui->baudRateL->setCurrentIndex(settings->value("BaudRate").toInt());
        }
        if(settings->contains(QString("DataBits"))){
            ui->dataBitsL->setCurrentIndex(settings->value("DataBits").toInt());
        }
        if(settings->contains(QString("Parity"))){
            ui->parityL->setCurrentIndex(settings->value("Parity").toInt());
        }
        if(settings->contains(QString("StopBits"))){
            ui->stopBitsL->setCurrentIndex(settings->value("StopBits").toInt());
        }
        settings->endGroup();
    }

    if(grouplist.contains(comR)){
        settings->beginGroup(comR);
        if(settings->contains(QString("Port"))){
            ui->portR->setCurrentText(settings->value("Port").toString());
        }
        if(settings->contains(QString("BaudRate"))){
            ui->baudRateR->setCurrentIndex(settings->value("BaudRate").toInt());
        }
        if(settings->contains(QString("DataBits"))){
            ui->dataBitsR->setCurrentIndex(settings->value("DataBits").toInt());
        }
        if(settings->contains(QString("Parity"))){
            ui->parityR->setCurrentIndex(settings->value("Parity").toInt());
        }
        if(settings->contains(QString("StopBits"))){
            ui->stopBitsR->setCurrentIndex(settings->value("StopBits").toInt());
        }
        settings->endGroup();
    }

    return true;
}

void SerialRepeaterWindow::saveConfig()
{
    const QString filename(QApplication::applicationName() + QString(".ini"));

    QSettings *settings;

    settings = new QSettings(filename, QSettings::IniFormat);
    settings->setValue("ComL/Port", ui->portL->currentText());
    settings->setValue("ComL/BaudRate", ui->baudRateL->currentIndex());
    settings->setValue("ComL/DataBits", ui->dataBitsL->currentIndex());
    settings->setValue("ComL/Parity", ui->parityL->currentIndex());
    settings->setValue("ComL/StopBits", ui->stopBitsL->currentIndex());

    settings->setValue("ComR/Port", ui->portR->currentText());
    settings->setValue("ComR/BaudRate", ui->baudRateR->currentIndex());
    settings->setValue("ComR/DataBits", ui->dataBitsR->currentIndex());
    settings->setValue("ComR/Parity", ui->parityR->currentIndex());
    settings->setValue("ComR/StopBits", ui->stopBitsR->currentIndex());

    settings->sync();
}

void SerialRepeaterWindow::closeEvent(QCloseEvent *env)
{
    exitActionTriggered();
    QMainWindow::closeEvent(env);
}

void SerialRepeaterWindow::startActionTriggered()
{
    QSerialPort::DataBits dataBits;
    QSerialPort::Parity parity;
    QSerialPort::StopBits stopBits;

    if(ui->portL->count() <= 0) return;
    if(ui->baudRateL->count() <= 0) return;
    if(ui->portR->count() <= 0) return;
    if(ui->baudRateR->count() <= 0) return;

    if (m_serialportL == nullptr) {
        switch (ui->dataBitsL->currentIndex()) {
        case 0:
            dataBits = QSerialPort::Data5;
            break;
        case 1:
            dataBits = QSerialPort::Data6;
            break;
        case 2:
            dataBits = QSerialPort::Data7;
            break;
        case 3:
            dataBits = QSerialPort::Data8;
            break;
        default:
            dataBits = QSerialPort::Data8;
            break;
        }
        switch (ui->parityL->currentIndex()) {
        case 0:
            parity = QSerialPort::NoParity;
            break;
        case 1:
            parity = QSerialPort::EvenParity;
            break;
        case 2:
            parity = QSerialPort::OddParity;
            break;
        case 3:
            parity = QSerialPort::SpaceParity;
            break;
        case 4:
            parity = QSerialPort::MarkParity;
            break;
        default:
            parity = QSerialPort::NoParity;
            break;
        }
        switch (ui->stopBitsL->currentIndex()) {
        case 0:
            stopBits = QSerialPort::OneStop;
            break;
        case 1:
            stopBits = QSerialPort::OneAndHalfStop;
            break;
        case 2:
            stopBits = QSerialPort::TwoStop;
            break;
        default:
            stopBits = QSerialPort::OneStop;
            break;
        }
        m_serialportL = openPort(ui->portL->currentText(),
                                 ui->baudRateL->currentText().toInt(),
                                 dataBits, parity, stopBits);
        if (m_serialportL == nullptr) {
            return;
        }
        switch (ui->dataBitsR->currentIndex()) {
        case 0:
            dataBits = QSerialPort::Data5;
            break;
        case 1:
            dataBits = QSerialPort::Data6;
            break;
        case 2:
            dataBits = QSerialPort::Data7;
            break;
        case 3:
            dataBits = QSerialPort::Data8;
            break;
        default:
            dataBits = QSerialPort::Data8;
            break;
        }
        switch (ui->parityR->currentIndex()) {
        case 0:
            parity = QSerialPort::NoParity;
            break;
        case 1:
            parity = QSerialPort::EvenParity;
            break;
        case 2:
            parity = QSerialPort::OddParity;
            break;
        case 3:
            parity = QSerialPort::SpaceParity;
            break;
        case 4:
            parity = QSerialPort::MarkParity;
            break;
        default:
            parity = QSerialPort::NoParity;
            break;
        }
        switch (ui->stopBitsR->currentIndex()) {
        case 0:
            stopBits = QSerialPort::OneStop;
            break;
        case 1:
            stopBits = QSerialPort::OneAndHalfStop;
            break;
        case 2:
            stopBits = QSerialPort::TwoStop;
            break;
        default:
            stopBits = QSerialPort::OneStop;
            break;
        }
        m_serialportR = openPort(ui->portR->currentText(),
                                 ui->baudRateR->currentText().toInt(),
                                 dataBits, parity, stopBits);
        if (m_serialportR == nullptr) {
            stopActionTriggered();
            return;
        }

        connect(m_serialportL, &QSerialPort::readyRead, this, &SerialRepeaterWindow::readyReadL);
        connect(m_serialportR, &QSerialPort::readyRead, this, &SerialRepeaterWindow::readyReadR);

        openEnable(true);

        m_l2r_cnt = 0;
        m_r2l_cnt = 0;
        ui->l2r_counter->setText(QString::number(m_l2r_cnt));
        ui->r2l_counter->setText(QString::number(m_r2l_cnt));
    }
}

void SerialRepeaterWindow::stopActionTriggered()
{
    if (m_serialportL != nullptr) {
        m_serialportL->close();
        delete m_serialportL;
        m_serialportL = nullptr;
    }

    if (m_serialportR != nullptr) {
        m_serialportR->close();
        delete m_serialportR;
        m_serialportR = nullptr;
    }
    openEnable(false);
}

void SerialRepeaterWindow::exitActionTriggered()
{
    saveConfig();
    stopActionTriggered();
    qApp->exit(0);
}

void SerialRepeaterWindow::readyReadL()
{
    QByteArray recv;
    QString info, detail;
    qint64 ret;

    recv = m_serialportL->readAll();
    m_serialportR->write(recv);
    ret = recv.length();

    m_l2r_cnt += ret;
    ui->l2r_counter->setText(QString::number(m_l2r_cnt));

    info = QString("L>R <%1>  %2").arg(ret).arg(QString::fromUtf8(recv));
    detail = QString('[') + recv.toHex(' ').toUpper() + QString(']');

    ui->info->showInfo(info, detail);
}

void SerialRepeaterWindow::readyReadR()
{
    QByteArray recv;
    QString info, detail;
    qint64 ret;

    recv = m_serialportR->readAll();
    m_serialportL->write(recv);
    ret = recv.length();

    m_r2l_cnt += ret;
    ui->r2l_counter->setText(QString::number(m_r2l_cnt));

    info = QString("R>L <%1>  %2").arg(ret).arg(QString::fromUtf8(recv));
    detail = QString('[') + recv.toHex(' ').toUpper() + QString(']');

    ui->info->showInfo(info, detail);
}

QSerialPort *SerialRepeaterWindow::openPort(const QString &port, qint32 baudRate, QSerialPort::DataBits dataBits, QSerialPort::Parity parity, QSerialPort::StopBits stopBits)
{
    int opened = 0;
    QSerialPort * serialPort = Q_NULLPTR;

    serialPort = new QSerialPort(this);

    if(!serialPort) return Q_NULLPTR;

    serialPort->setPortName(port);
    serialPort->setBaudRate(baudRate);
    serialPort->setDataBits(dataBits);
    serialPort->setParity(parity);
    serialPort->setStopBits(stopBits);

    opened = serialPort->open(QSerialPort::ReadWrite);

    if(!opened){
        ui->info->showInfo(serialPort->portName() + serialPort->errorString());
        delete serialPort;
        serialPort = Q_NULLPTR;
    }

    return serialPort;
}

void SerialRepeaterWindow::openEnable(bool enable)
{
    ui->portL->setEnabled(!enable);
    ui->baudRateL->setEnabled(!enable);
    ui->dataBitsL->setEnabled(!enable);
    ui->parityL->setEnabled(!enable);
    ui->stopBitsL->setEnabled(!enable);
    ui->portR->setEnabled(!enable);
    ui->baudRateR->setEnabled(!enable);
    ui->dataBitsR->setEnabled(!enable);
    ui->parityR->setEnabled(!enable);
    ui->stopBitsR->setEnabled(!enable);
}
